#ifndef BINARY_PROTOCOL_H
#define	BINARY_PROTOCOL_H

#include <stdint.h>

typedef enum {
  CMD_GET   =  0x00,
  CMD_BGET  =  0x40,
  CMD_BGETQ =  0x41,
  CMD_MGET  =  0x42, //<== use this
  CMD_GETQ  =  0x09,
  CMD_GETK  =  0x0c,
  CMD_GETKQ =  0x0d,
  CMD_SET   =  0x01,
  CMD_SASL  =  0x21,
  CMD_NOOP  =  0x0a

} protocol_binary_command;

#define RESP_OK 0x00
#define RESP_SASL_ERR 0x20

#define MAX_BATCH_GET_SZ

typedef union __attribute__ ((__packed__)) {
    struct {
        uint16_t ip;
        uint16_t port;
    } c_info;
    uint32_t opq;
} opaque_info;

typedef struct __attribute__ ((__packed__)) {
  uint8_t magic;
  uint8_t opcode;
  uint16_t key_len;

  uint8_t extra_len;
  uint8_t data_type;
  union {
   uint16_t vbucket; // request use
   uint16_t status;  // response use
  };

  uint32_t body_len;
  union {
      struct {
          uint16_t src_ip;
          uint16_t src_port;
      };
      uint32_t opaque;
  };
  uint64_t cas;

} binary_header_t;

typedef struct __attribute__ ((__packed__)) {
    binary_header_t header;
} binary_get_req_header;

typedef binary_get_req_header binary_set_resp_header;

typedef struct __attribute__ ((__packed__)) {
    binary_header_t header;
    struct {
        uint32_t flags;
    } extras;
} binary_get_resp_header;

typedef struct __attribute__ ((__packed__)) {
    binary_header_t header;
    struct {
        // Used for set only.
        uint32_t flags;
        uint32_t expiration;
    } extras;
} binary_set_req_header;

typedef struct __attribute__ ((__packed__)) {
    binary_header_t header;
    struct {
        uint32_t req_ip;
        uint16_t req_port;
        uint16_t req_seq_number;
    } extras;
} binary_bget_req_header;

typedef struct __attribute__ ((__packed__)) {
    binary_header_t header;
    struct {
        uint32_t flags;
        uint32_t req_ip;
        uint16_t req_port;
        uint16_t req_seq_number;
    } extras;
} binary_bget_resp_header;

typedef struct __attribute__ ((__packed__)) {
    union {
        struct {
            uint16_t req_src_ip;
            uint16_t req_src_port;
        };
        uint32_t opaque;
    };
    uint16_t k_len;
    uint64_t cas;
} req_meta;

typedef req_meta get_req_meta;

typedef struct __attribute__ ((__packed__)) {
    req_meta meta;
    uint32_t v_len;
} set_req_meta;

// typedef struct __attribute__ ((__packed__)) {
//     //uint8_t num_requests;
//     get_req_meta req_meta_list[MAX_BATCH_GET_SZ];
// } get_req_list;

typedef struct __attribute__ ((__packed__)) {
    uint8_t magic;
    uint8_t opcode;
    uint16_t num_requests;  // number of requests

    uint16_t meta_len;     // length of req_meta_list (original uint8_t)
    //uint8_t data_type;
    uint32_t body_len;     // length of (meta_len + sizeof(keys)

} binary_mget_header_test;

typedef struct __attribute__ ((__packed__)) {
    uint8_t magic;
    uint8_t opcode;    //CMD_MGET
    uint16_t num_keys; //number of keys

    uint8_t extra_len; //0
    uint8_t data_type;
    union {
        uint16_t vbucket; //request use
        uint16_t status;  //response use
    };

    uint32_t body_len;  //0 or length of sum(get_request)
    uint32_t opaque;    //0x0
    uint64_t cas;       //0x0

} binary_mget_header_t;   //used as multi-get requests header

typedef struct _TCPheader {
	uint8_t type; // 1
	uint8_t src_ip;  // 1 +1
	uint16_t port; // 2 +2
	uint16_t num_msg; // 2 +4
	uint16_t len_msg; // 2 +6
    //uint32_t ack; // 4 +8
} TCPheader; // 12  [12]

#endif /* BINARY_PROTOCOL_H */
